package simorg;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;

class Unknown implements Comparable<Unknown> {
	public final static int NEGATIVE_RESULT = -1;

	private final int NUM_TESTS = 24 + 21;

	private final int m_id;

	private final String m_unknownClass;

	private final String m_commonName;
	private final String m_iupacName;
	private final int m_meltingPoint;

	private final int m_boilingPoint;

	private final int m_use;

	// NOTE: [ 0 ] = D2, [ NUM_DERIVATIVES ] = T2
	private final HashMap<Test, TestResult> m_resultsMap = new HashMap<Test, TestResult>();

	public Unknown(final ResultSet a_row) {
		try {
			final int ID_COLUMN = 1;
			final int COMMON_NAME_COLUMN = 2;
			final int IUPAC_NAME_COLUMN = 3;
			final int UNKNOWN_CLASS_COLUMN = 4;
			final int MELTING_POINT_COLUMN = 5;
			final int BOILING_POINT_COLUMN = 6;
			final int USE_COLUMN = 7;
			final int TEST_START = 8;
			final int TEST_END = TEST_START + NUM_TESTS;

			m_id = a_row.getInt(ID_COLUMN);

			// System.out.println( "Loading unknown " + m_id );

			m_commonName = a_row.getString(COMMON_NAME_COLUMN);
			m_iupacName = a_row.getString(IUPAC_NAME_COLUMN);

			m_unknownClass = a_row.getString(UNKNOWN_CLASS_COLUMN);

			// TODO melting/boiling point = 0 means no mp/bp... should allow 0
			// value

			// no melting point = max int
			final int meltingPoint = a_row.getInt(MELTING_POINT_COLUMN);
			if (meltingPoint == 0) {
				m_meltingPoint = Integer.MAX_VALUE;
			} else {
				m_meltingPoint = meltingPoint;
			}

			// no boiling point = max int
			final int boilingPoint = a_row.getInt(BOILING_POINT_COLUMN);
			if (boilingPoint == 0) {
				m_boilingPoint = Integer.MAX_VALUE;
			} else {
				m_boilingPoint = boilingPoint;
			}

			m_use = a_row.getInt(USE_COLUMN);

			final DatabaseInterface dbInterface = DatabaseInterface
					.getSingleton();

			// read test results
			// note: derivative tests are listed after classification tests,
			// each with a unique internal ID
			// TODO: left/right values
			// System.out.print( "Unknown #" + m_id + " results: " );
			for (int column = TEST_START; column < TEST_END; column++) {
				// System.out.println( "Reading result " + column );

				String entry = a_row.getString(column).trim();

				int stringId = 0;
				final int testId = column - TEST_START + 2;
				TestResult.ExtraType extra = TestResult.ExtraType.NONE;

				// blank entry means NEGATIVE result
				if (entry == null || entry.isEmpty()) {
					stringId = NEGATIVE_RESULT;
				} else {

					// if we have extra type flags, use them
					if (entry.contains("(di)")) {
						extra = TestResult.ExtraType.D_I_PAREN;
						entry = entry.replace("(di)", "");
					} else if (entry.contains("d.")) {
						extra = TestResult.ExtraType.D_DOT;
						entry = entry.replace("d.", "");
					} else if (entry.contains("d")) {
						extra = TestResult.ExtraType.D;
						entry = entry.replace("d", "");
					}

					// if we have a dot, only take the left side
					if (entry.contains(".")) {
						final String left = entry.substring(0, entry
								.indexOf("."));
						final String right = entry
								.substring(entry.indexOf(".") + 1);

						// one of these is preferred
						// stringId = Integer.parseInt( right );
						stringId = Integer.parseInt(left);
					}
				}

				// add the result to the test
				final Test test = dbInterface.getTest(testId);
				final TestResult result = dbInterface.addResult(stringId,
						testId);

				// set the extra type
				result.setExtra(extra);

				if (extra != TestResult.ExtraType.NONE) {
					// System.out.println( "Extra type: " + extra.ordinal() );
				}

				m_resultsMap.put(test, result);
			}
			// System.out.println();

		} catch (final SQLException sqlex) {
			sqlex.printStackTrace();

			// invalid row
			throw new IllegalArgumentException();
		}
	}

	public int compareTo(final Unknown a_unknown) {
		return getId() - a_unknown.getId();
	}

	public void dbgListResults() {
		System.out.print("Results for " + getCommonName() + ": ");

		for (final Test test : m_resultsMap.keySet()) {
			System.out.print(test.getName() + " ("
					+ m_resultsMap.get(test).getResult() + ") ");
		}

		System.out.println();
	}

	public int getBoilingPoint() {
		if (m_boilingPoint == Integer.MAX_VALUE) {
			throw new RuntimeException(
					"Attempted to retrieve boiling point from unknown with no BP.");
		}

		return m_boilingPoint;
	}

	public String getCommonName() {
		return m_commonName;
	}

	public String getFullName() {
		return "'" + getCommonName() + "' (" + getId() + ")";
	}

	public int getId() {
		return m_id;
	}

	public String getIupacName() {
		return m_iupacName;
	}

	public int getMeltingPoint() {
		if (m_meltingPoint == Integer.MAX_VALUE) {
			throw new RuntimeException(
					"Attempted to retrieve melting point from unknown with no MP.");
		}

		return m_meltingPoint;
	}

	public TestResult getResult(final Test a_test) {
		final TestResult result = m_resultsMap.get(a_test);

		if (result == null || result.getResult() == 0) {
			return null;
		} else {
			return result;
		}
	}

	public String getUnknownClass() {
		return m_unknownClass;
	}

	public int getUse() {
		return m_use;
	}

	public boolean hasBoilingPoint() {
		return m_boilingPoint < Integer.MAX_VALUE;
	}

	public boolean hasMeltingPoint() {
		return m_meltingPoint < Integer.MAX_VALUE;
	}

	public boolean hasResult(final TestResult a_result) {
		return m_resultsMap.keySet().contains(a_result);
	}

	@Override
	public String toString() {
		return this.getCommonName();
	}
}